package com.tomtop.core.redis;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.google.common.collect.Maps;
import com.tomtop._const.Const;
import com.tomtop.core._enum.CustomStatus;
import com.tomtop.core.exception.CustomException;

public class  EnableTransactionIntegerRedisTemplate extends RedisTemplate<String, Integer>{
	Logger Logger = LoggerFactory .getLogger(EnableTransactionIntegerRedisTemplate.class);
	public EnableTransactionIntegerRedisTemplate() {
		RedisSerializer<String> stringSerializer = new StringRedisSerializer();
		RedisSerializer<Integer> integerSerializer = new RedisSerializer<Integer>() {
			public Integer deserialize(byte[] bytes) { return (bytes == null ? null : Integer.parseInt(new String(bytes))); }
			public byte[] serialize(Integer integer) { return (integer == null ? null : String.valueOf(integer).getBytes()); }
		};
		setKeySerializer(stringSerializer);
		setValueSerializer(integerSerializer);
		setHashKeySerializer(stringSerializer);
		setHashValueSerializer(integerSerializer);
		setEnableTransactionSupport(true);
	}
	public EnableTransactionIntegerRedisTemplate(RedisConnectionFactory connectionFactory) {
		this();
		setConnectionFactory(connectionFactory);
		afterPropertiesSet();
	}

	protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
		return new DefaultStringRedisConnection(connection);
	}
	public void multiUpdate(Map<String,Integer> oasm){
		for (int i = 0; i < Const.REDIS_TRANSACTION_RETRY_NUMBER; i++)
			try{
				this.multiUpdateExec(oasm);
				break;
			}catch (RedisSystemException e) {
				Logger.info("redis提交事务失败");
				if(i>Const.REDIS_TRANSACTION_RETRY_NUMBER ){
					Logger.error("修改redis失败，redis提交事务超过{}次仍然未完成",Const.REDIS_TRANSACTION_RETRY_NUMBER,e);
					throw new CustomException(CustomStatus.UPDATE_REDIS_FAIL);
				}
				Logger.info("已重试{}次，在次重试提交",i);
			}finally {
				this.unbind();
			}
	}
	protected void multiUpdateExec(Map<String,Integer> oasm ){
		Map<String, Integer> poasm=Maps.newHashMap();
		this.watch(oasm.keySet());
		oasm.keySet().forEach((rediskey)->{
			int qty=oasm.get(rediskey);
			if(this.hasKey(rediskey)){
				Integer rqty= this.opsForValue().get(rediskey);
				if(rqty!=null)
					qty+=rqty;
				if(qty<0){
					Logger.error("redis 值修改后不可以小于0");
					throw new CustomException(CustomStatus.UPDATE_REDIS_FAIL);
				}
			}
			poasm.put(rediskey, qty);
		});
		this.multi();
		this.opsForValue().multiSet(poasm);
		this.exec();
	}
	public void unbind() {
		  RedisConnectionUtils.unbindConnection(getConnectionFactory());
	}
}
